package com.chinameyer.workorders.service;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinameyer.workorders.bean.MeyerUser;
import com.chinameyer.workorders.dto.user.ChangePasswordDTO;
import com.chinameyer.workorders.dto.user.CreateUserDTO;
import com.chinameyer.workorders.dto.user.LoginDTO;
import com.chinameyer.workorders.dto.user.UpdateUserDTO;
import com.chinameyer.workorders.mapper.UserMapper;
import com.chinameyer.workorders.utils.RandomStringUtil;
import com.chinameyer.workorders.vo.LoginVO;
import com.chinameyer.workorders.vo.UserVO;
import com.xinmachong.jwt.JWTUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @Author meyer@HongYe
 */
@Service
public class UserService {

    @Resource
    private UserMapper userMapper;

    @Transactional
    public String getSaltByAccount(LoginDTO loginDTO) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getAccount,loginDTO.getAccount());
        return this.userMapper.selectOne(wrapper).getSalt();
    }

    public String getPasswordByAccount(LoginDTO loginDTO) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getAccount,loginDTO.getAccount());
        return this.userMapper.selectOne(wrapper).getPassword();
    }

    public LoginVO getUserMsg(LoginDTO loginDTO) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getAccount,loginDTO.getAccount());
        MeyerUser meyerUser = this.userMapper.selectOne(wrapper);
        String token = this.getToken(meyerUser);
        boolean admin = false;
        if (meyerUser.getAdmin() == 1) {
            admin = true;
        }

        LoginVO loginVO = new LoginVO();
        loginVO.setToken(token);
        loginVO.setAdmin(admin);
        BeanUtils.copyProperties(meyerUser,loginVO);
        return loginVO;
    }

    public String getToken(MeyerUser meyerUser) {
        Map<String,String> payload = new HashMap<>();
        payload.put("userId", meyerUser.getId()+"");
        payload.put("username", meyerUser.getUsername());
        payload.put("account", meyerUser.getAccount());
        return JWTUtils.getToken(payload);
    }

    public boolean checkStaffNoIsExist(CreateUserDTO createUserDTO) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getStaffNo,createUserDTO.getStaffNo());
        return this.userMapper.selectCount(wrapper) > 0;
    }

    @Transactional
    public void addUser(CreateUserDTO createUserDTO) {
        String salt = RandomStringUtil.generateString(new Random(), RandomStringUtil.SOURCES,4);
        String encodedPassword = new SimpleHash("MD5","123456",salt,1).toHex();
        MeyerUser user = new MeyerUser();
        BeanUtils.copyProperties(createUserDTO,user);
        user.setAccount(createUserDTO.getStaffNo()).setSalt(salt).setPassword(encodedPassword);
        this.userMapper.insert(user);
    }

    @Transactional
    public void deleteUser(int userId) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getId,userId);
        this.userMapper.delete(wrapper);
    }

    public boolean checkStaffNoIsExistExpectItself(UpdateUserDTO updateUserDTO) {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(MeyerUser::getStaffNo,updateUserDTO.getStaffNo()).ne(MeyerUser::getId,updateUserDTO.getId());
        return this.userMapper.selectCount(wrapper) > 0;
    }

    @Transactional
    public void editUser(UpdateUserDTO updateUserDTO) {
        MeyerUser user = this.userMapper.selectById(updateUserDTO.getId());
        BeanUtils.copyProperties(updateUserDTO,user);
        user.setAccount(updateUserDTO.getStaffNo());
        this.userMapper.updateById(user);
    }

    public List<UserVO> getAllUsers(int count, int page) {
        int start = count * page;
        int limit = count;
        List<MeyerUser> userList = this.userMapper.selectAllUsersWithPage(start,limit);
        List<UserVO> userVOList = new ArrayList<>();
        userList.forEach(user -> {
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(user,userVO);
            userVOList.add(userVO);
        });
        return userVOList;
    }

    public int getAllUsersTotal() {
        QueryWrapper<MeyerUser> wrapper = new QueryWrapper<>();
        wrapper.lambda().isNull(MeyerUser::getDeleteTime);
        return this.userMapper.selectCount(wrapper);
    }

    @Transactional
    public void changePassword(HttpServletRequest request, ChangePasswordDTO changePasswordDTO) {
        MeyerUser user = this.getUser(request);
        String password = new SimpleHash("MD5",changePasswordDTO.getNewPassword(),user.getSalt(),1).toHex();
        user.setPassword(password);
        this.userMapper.updateById(user);
    }

    private MeyerUser getUser(HttpServletRequest request) {
        String token = request.getHeader("token");
        DecodedJWT verify = JWTUtils.verify(token);
        int userId =  Integer.parseInt(verify.getClaim("userId").asString());
        return this.userMapper.selectById(userId);
    }
}
